package moonlit.chill.pay.util;

import cn.hutool.core.io.FileUtil;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import lombok.extern.slf4j.Slf4j;
import moonlit.chill.pay.cache.PayConfigDataCache;
import moonlit.chill.pay.constants.PayType;
import moonlit.chill.pay.exception.PayException;
import moonlit.chill.pay.vo.PayConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.io.File;
import java.nio.file.FileSystems;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author MoonlitChill
 * @date 2024/4/24 9:24
 */
@Slf4j
@Component
@Configuration
public class PayUtil {

    @Autowired
    private PayConfigDataCache payConfigDataCache;

    private static final String SEPARATOR = FileSystems.getDefault().getSeparator();

    @Bean("aliClient")
    public Map<String, Object> getAlipayClientMap() {
        List<PayConfig> list = payConfigDataCache.getPayConfigByPayType(PayType.ALI);
        if (list.isEmpty()){
            log.error("生成支付宝证书获取PayConfig为空");
            return new HashMap<>();
        }
        Map<String, Object> map = new HashMap<>();
        for (PayConfig payConfig : list) {
            String pre = System.getProperty("user.dir") + SEPARATOR + "alicrt" + SEPARATOR + payConfig.getUId() + SEPARATOR;
            String appCertPath = pre + "appCertPublicKey.crt";
            String aliPayCertPath = pre + "alipayCertPublicKey.crt";
            String aliPayRootCertPath = pre + "alipayRootCert.crt";
            try {
                boolean appCertExist = FileUtil.exist(appCertPath);
                if (!appCertExist) {
                    File appCertFile = FileUtil.touch(appCertPath);
                    appCertFile = FileUtil.writeUtf8String(payConfig.getAppCertPath(), appCertFile);
                    boolean exist = FileUtil.exist(appCertFile);
                    if (!exist) {
                        throw new PayException("生成支付宝appCertPublicKey证书失败");
                    }
                }
                boolean aliPayCertExist = FileUtil.exist(aliPayCertPath);
                if (!aliPayCertExist) {
                    File aliPayCertFile = FileUtil.touch(aliPayCertPath);
                    aliPayCertFile = FileUtil.writeUtf8String(payConfig.getAliPayCertPath(), aliPayCertFile);
                    boolean exist = FileUtil.exist(aliPayCertFile);
                    if (!exist) {
                        throw new PayException("生成支付宝alipayCertPublicKey证书失败");
                    }
                }
                boolean aliPayRootCertExist = FileUtil.exist(aliPayRootCertPath);
                if (!aliPayRootCertExist) {
                    File aliPayRootCertFile = FileUtil.touch(aliPayRootCertPath);
                    aliPayRootCertFile = FileUtil.writeUtf8String(payConfig.getAliPayRootCertPath(), aliPayRootCertFile);
                    boolean exist = FileUtil.exist(aliPayRootCertFile);
                    if (!exist) {
                        throw new PayException("生成支付宝alipayRootCert证书失败");
                    }
                }
                CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
                certAlipayRequest.setServerUrl(payConfig.getGateWayUrl());
                certAlipayRequest.setAppId(payConfig.getAppId());
                certAlipayRequest.setPrivateKey(payConfig.getPrivateKey());
                certAlipayRequest.setFormat("json");
                certAlipayRequest.setCharset("utf-8");
                certAlipayRequest.setSignType("RSA2");
                certAlipayRequest.setCertPath(appCertPath);
                certAlipayRequest.setAlipayPublicCertPath(aliPayCertPath);
                certAlipayRequest.setRootCertPath(aliPayRootCertPath);
                map.put(payConfig.getCode(), new DefaultAlipayClient(certAlipayRequest));
                map.put(payConfig.getCode() + "_aliPayCertPath", aliPayCertPath);
            } catch (Exception e) {
                log.error("生成支付宝证书失败:{}", e.getMessage(), e);
                throw new PayException("发起支付异常，请联系管理员");
            }
        }
        return map;
    }

    @Bean("wxConfig")
    public Map<String, Object> getWxConfigMap() {
        List<PayConfig> list = payConfigDataCache.getPayConfigByPayType(PayType.WX);
        if (list.isEmpty()){
            log.error("生成微信证书获取PayConfig为空");
            return new HashMap<>();
        }
        Map<String, Object> map = new HashMap<>();
        for (PayConfig payConfig : list) {
            String pre = System.getProperty("user.dir") + SEPARATOR + "wxcrt" + SEPARATOR + payConfig.getUId() + SEPARATOR;
            String keyFilePath = pre + "apiclient_key.pem";
            String certFilePath = pre + "apiclient_cert.pem";
            try {
                boolean keyCertExist = FileUtil.exist(keyFilePath);
                if (!keyCertExist) {
                    File keyFile = FileUtil.touch(keyFilePath);
                    keyFile = FileUtil.writeUtf8String(payConfig.getKeyCertPath(), keyFile);
                    boolean exist = FileUtil.exist(keyFile);
                    if (!exist) {
                        throw new PayException("生成微信apiclient_key.pem证书失败");
                    }
                }
                boolean certExist = FileUtil.exist(certFilePath);
                if (!certExist) {
                    File certFile = FileUtil.touch(certFilePath);
                    certFile = FileUtil.writeUtf8String(payConfig.getCertPath(), certFile);
                    boolean exist = FileUtil.exist(certFile);
                    if (!exist) {
                        throw new PayException("生成微信apiclient_cert.pem证书失败");
                    }
                }
            } catch (Exception e) {
                log.error("生成微信证书失败:{}", e.getMessage(), e);
                throw new PayException("发起支付异常，请联系管理员");
            }
            RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(payConfig.getUId())
                    .privateKeyFromPath(keyFilePath)
                    .merchantSerialNumber(WxCertUtil.getCertificateSerialNumber(certFilePath))
                    .apiV3Key(payConfig.getCertKey())
                    .build();
            map.put(payConfig.getCode(), config);
            //异步回调使用
            map.put(payConfig.getCode() + "_keyCertPath", keyFilePath);
            map.put(payConfig.getCode() + "_certPath", certFilePath);
        }
        return map;
    }
}
